home *** CD-ROM | disk | FTP | other *** search
- /*
- - Routines to open a TCP connection
- *
- * New version that supports the old (pre 4.2 BSD) socket calls,
- * and systems with the old (pre 4.2 BSD) hostname lookup stuff.
- * Compile-time options are:
- *
- * NONETDB - old hostname lookup with rhost()
- * OLDSOCKET - different args for socket() and connect()
- * DKHOST - for DKHOST support
- *
- * Erik E. Fair <fair@ucbarpa.berkeley.edu>
- *
- */
-
- #include "conf.h"
-
- #ifdef DKHOST
- #include <dk.h>
- #endif
- #include <sys/socket.h>
- #ifdef FAKESYSLOG
- #include "fsyslog.h"
- #else
- #include <syslog.h>
- #endif
- #include <netinet/in.h>
- #include <ctype.h>
- #include "readline.h"
- #include "nntplink.h"
-
- extern char *Prog_name;
- extern int Nntp_port;
-
- #ifdef EXCELAN
- #define NONETDB
- #define OLDSOCKET
- #endif
-
- #ifdef NONETDB
- #define IPPORT_NNTP 119 /* NNTP is on TCP port 119 */
- #else
- #include <netdb.h>
- #endif
-
- #ifndef htons
- extern unsigned short htons();
- #endif
- #ifndef NONETDB
- extern char *inet_ntoa();
- extern unsigned long inet_addr();
- #else
- /*
- * inet_addr for EXCELAN (which does not have it!)
- *
- */
- unsigned long
- inet_addr(cp)
- register char *cp;
- {
- unsigned long val, base, n;
- register char c;
- unsigned long octet[4], *octetptr = octet;
- #ifndef htonl
- extern unsigned long htonl();
- #endif
- again:
- /*
- * Collect number up to ``.''.
- * Values are specified as for C:
- * 0x=hex, 0=octal, other=decimal.
- */
- val = 0; base = 10;
- if (*cp == '0')
- base = 8, cp++;
- if (*cp == 'x' || *cp == 'X')
- base = 16, cp++;
- while (c = *cp) {
- if (isdigit(c)) {
- val = (val * base) + (c - '0');
- cp++;
- continue;
- }
- if (base == 16 && isxdigit(c)) {
- val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A'));
- cp++;
- continue;
- }
- break;
- }
- if (*cp == '.') {
- /*
- * Internet format:
- * a.b.c.d
- * a.b.c (with c treated as 16-bits)
- * a.b (with b treated as 24 bits)
- */
- if (octetptr >= octet + 4)
- return FAIL;
- *octetptr++ = val, cp++;
- goto again;
- }
- /*
- * Check for trailing characters.
- */
- if (*cp && !isspace(*cp))
- return FAIL;
- *octetptr++ = val;
- /*
- * Concoct the address according to
- * the number of octet specified.
- */
- n = octetptr - octet;
- switch (n) {
-
- case 1: /* a -- 32 bits */
- val = octet[0];
- break;
-
- case 2: /* a.b -- 8.24 bits */
- val = (octet[0] << 24) | (octet[1] & 0xffffff);
- break;
-
- case 3: /* a.b.c -- 8.8.16 bits */
- val = (octet[0] << 24) | ((octet[1] & 0xff) << 16) |
- (octet[2] & 0xffff);
- break;
-
- case 4: /* a.b.c.d -- 8.8.8.8 bits */
- val = (octet[0] << 24) | ((octet[1] & 0xff) << 16) |
- ((octet[2] & 0xff) << 8) | (octet[3] & 0xff);
- break;
-
- default:
- return FAIL;
- }
- val = htonl(val);
- return val;
- }
-
- char *
- inet_ntoa(in)
- struct in_addr in;
- {
- static char address[20];
-
- sprintf(address, "%u.%u.%u.%u",
- (in.s_addr>>24)&0xff,
- (in.s_addr>>16)&0xff,
- (in.s_addr>>8 )&0xff,
- (in.s_addr )&0xff);
- return address;
- }
- #endif /* NONETDB */
-
- /*
- * Take the name of an internet host in ASCII (this may either be its
- * official host name or internet number (with or without enclosing
- * backets [])), and return a list of internet addresses.
- *
- * returns NULL for failure to find the host name in the local database,
- * or for a bad internet address spec.
- */
- unsigned long **
- name_to_address(host)
- char *host;
- {
- static unsigned long *host_addresses[2];
- static unsigned long haddr;
-
- if (host == NULL) {
- return NULL;
- }
-
- host_addresses[0] = &haddr;
- host_addresses[1] = NULL;
-
- /*
- * Is this an ASCII internet address? (either of [10.0.0.78] or
- * 10.0.0.78). We get away with the second test because hostnames
- * and domain labels are not allowed to begin in numbers.
- * (cf. RFC952, RFC882).
- */
- if (*host == '[' || isdigit(*host)) {
- char namebuf[128];
- register char *cp = namebuf;
-
- /*
- * strip brackets [] or anything else we don't want.
- */
- while(*host != '\0' && cp < &namebuf[sizeof(namebuf) - 1]) {
- if (isdigit(*host) || *host == '.')
- *cp++ = *host++; /* copy */
- else
- host++; /* skip */
- }
- *cp = '\0';
- haddr = inet_addr(namebuf);
- return &host_addresses[0];
- } else {
- #ifdef NONETDB
- extern unsigned long rhost();
-
- /* lint is gonna bitch about this (comparing an unsigned?!) */
- if ((haddr = rhost(&host)) == FAIL)
- return NULL; /* no such host */
- return &host_addresses[0];
- #else
- struct hostent *hstp = gethostbyname(host);
-
- if (hstp == NULL) {
- return NULL; /* no such host */
- }
-
- if (hstp->h_length != sizeof(unsigned long))
- abort(); /* this is fundamental */
- #ifndef h_addr
- /* alignment problems (isn't dbm wonderful?) */
- memcpy((caddr_t)&haddr, (caddr_t)hstp->h_addr, sizeof(haddr));
- return &host_addresses[0];
- #else
- return (unsigned long **)hstp->h_addr_list;
- #endif /* h_addr */
- #endif /* NONETDB */
- }
- }
-
- /*
- * Get a service port number from a service name (or ASCII number)
- *
- * Return zero if something is wrong (that's a reserved port)
- */
- #ifdef NONETDB
- static struct Services {
- char *name;
- unsigned short port;
- } Services[] = {
- {"nntp", IPPORT_NNTP}, /* RFC977 */
- {"smtp", IPPORT_SMTP}, /* RFC821 */
- {"name", IPPORT_NAMESERVER}, /* RFC881, RFC882, RFC883 */
- {"time", IPPORT_TIMESERVER}, /* RFC868 */
- {"echo", IPPORT_ECHO}, /* RFC862 */
- {"discard", IPPORT_DISCARD}, /* RFC863 */
- {"daytime", IPPORT_DAYTIME}, /* RFC867 */
- {"login", IPPORT_LOGINSERVER}, /* N/A - 4BSD specific */
- };
- #endif /* NONETDB */
-
- unsigned short
- gservice(serv, proto)
- char *serv, *proto;
- {
- if (serv == NULL || proto == NULL)
- return (unsigned short)0;
-
- if (isdigit(*serv)) {
- return htons((unsigned short)(atoi(serv)));
- } else {
- #ifdef NONETDB
- register int i;
-
- for(i = 0; i < (sizeof(Services) / sizeof(struct Services)); i++) {
- if (strcmp(serv, Services[i].name) == 0)
- return htons(Services[i].port);
- }
- return (unsigned short)0;
- #else
- struct servent *srvp = getservbyname(serv, proto);
-
- if (Nntp_port && !strcmp(serv,"nntp"))
- return htons((unsigned short)Nntp_port);
-
- if (srvp == NULL)
- return (unsigned short)0;
- return (unsigned short)srvp->s_port;
- #endif /* NONETDB */
- }
- }
-
- /*
- * given a host name (either name or internet address) and service name
- * (or port number) (both in ASCII), give us a TCP connection to the
- * requested service at the requested host (or give us FAIL).
- */
- get_tcp_conn(host, serv)
- char *host, *serv;
- {
- #ifdef USE_KEEPALIVES
- int on = 1;
- #endif
- static char *fname = "get_tcp_conn: ";
- int e_save;
- register int sock;
- unsigned long **addrlist;
- struct sockaddr_in sadr;
- #ifdef OLDSOCKET
- struct sockproto sp;
-
- sp.sp_family = (unsigned short)AF_INET;
- sp.sp_protocol = (unsigned short)IPPROTO_TCP;
- #endif /* OLDSOCKET */
-
- if ((addrlist = name_to_address(host)) == NULL)
- return NOHOST;
-
- sadr.sin_family = (unsigned short)AF_INET; /* Only internet for now */
- if ((sadr.sin_port = gservice(serv, "tcp")) == 0)
- return NOSERVICE;
-
- for(; *addrlist != NULL; addrlist++) {
- memcpy((caddr_t)&sadr.sin_addr, (caddr_t)*addrlist,
- sizeof(sadr.sin_addr));
-
- #ifdef OLDSOCKET
- if ((sock = socket(SOCK_STREAM, &sp, NULL, 0)) < 0)
- return FAIL;
-
- if (connect(sock, (struct sockaddr *)&sadr) < 0) {
- #else
- if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
- return FAIL;
-
- if (connect(sock, (struct sockaddr *)&sadr, sizeof(sadr)) < 0) {
- #endif /* OLDSOCKET */
- e_save = errno;
- (void) close(sock); /* dump descriptor */
- errno = e_save;
- } else {
- #ifdef USE_KEEPALIVES
- if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
- (char *)&on, sizeof(on)) == FAIL)
- log(LOG_INFO, fname,
- "%s%s[%s]: setsockopt KEEPALIVE: %s\n",
- Host.name, inet_ntoa(sadr.sin_addr), errmsg(errno));
- #endif
- return sock;
- }
- }
- return FAIL;
- }
-
- #ifdef DKHOST
-
- /*
- * get_dk_conn -- get a DKHOST connection to an NNTP server
- *
- * Parameters: "machine is the name of the NNTP server.
- *
- * Returns: file descriptor for the service, or a "-1" in
- * case of failure.
- *
- * Side effects: connects to server.
- *
- * NOTE: "machine" has to have an entry in the dkhosts file on the
- * client, or DKHOST nntplink will bomb
- *
- */
-
- get_dk_conn(machine)
- char *machine;
- {
- #ifdef DKR_BLOCK
- #ifdef DKR_TIME
- static short dkrmode[3] = {DKR_BLOCK|DKR_TIME, 0, 0};
- #endif
- #endif
- static short timeout=500; /* read timeout in ms */
- char *maphost(), *dialstring;
- int dkfd;
- /* if( (dialstring = maphost( machine, 'f', "nntp", "", "-g:%f:-u:%u" )) == (char *)NULL ) */
- if( (dialstring = maphost( machine, 'f', "nntp", "", "-g:%f" )) == (char *)NULL )
- return(-1);
- if( (dkfd = dkdial(dialstring)) >= 0 ) {
- #ifdef TCDKITIME
- ioctl(dkfd, TCDKITIME, &timeout);
- #endif
- #ifdef DIOCRMODE
- ioctl(dkfd, DIOCRMODE, dkrmode);
- #endif
- } else
- dkfd = -1;
- return(dkfd);
- }
- #endif /* DKHOST */
-